﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Windows.Forms;
using SSAT.ConnectionStringsManagement;
using SSAT.Utils;
using SSAT.Utils.Freezer;
using System.Drawing;

namespace SSAT.Forms
{
    public partial class ConnectionForm : Form
    {
        private readonly ControlFreezer _refreshOperationFreezer = new ControlFreezer();
        private readonly ControlFreezer _connectOperationFreezer = new ControlFreezer();
        private SqlConnection _connectionToDb;

        public SqlConnection Connection
        {
            get { return _connectionToDb; }
            set { _connectionToDb = value; }
        }

        private class ServersComboBoxItem
        {
            public readonly SqlConnection Connection;

            public ServersComboBoxItem(string connectionString)
            {
                Connection = new SqlConnection(connectionString);
            }

            public override string ToString()
            {
                return Connection.DataSource;
            }
        }

        public ConnectionForm()
        {
            InitializeComponent();
            SetupControlFreezers();
            LoadPreviousConnectionStrings();
            Icon = System.Drawing.Icon.FromHandle(Resources.Connect.GetHicon());
        }

        private void SetupControlFreezers()
        {
            _refreshOperationFreezer.AddAListOfControls(new Control[] { btnUpdateServers, btnConnect, cbServers });
            _connectOperationFreezer.AddAListOfControls(new Control[] { btnUpdateServers, btnConnect, btnCancel, cbServers });

            _refreshOperationFreezer.OnUnfreezed += OnControlsUnfreezed;
            _connectOperationFreezer.OnUnfreezed += OnControlsUnfreezed;
        }

        public ConnectionForm(SqlConnection connection)
            : this()
        {
            if (connection != null)
            {
                ExtractConnectionStringInfo(connection);
            }
        }

        private void LoadPreviousConnectionStrings()
        {
            ConnectionStringsStorage storage = new ConnectionStringsStorage();
            storage.Load();
            foreach (KeyValuePair<string, string> item in storage)
            {
                AddToServersComboBox(item.Value);
            }
        }

        private void AddToServersComboBox(string connectionString)
        {
            cbServers.Items.Add(new ServersComboBoxItem(connectionString));
        }

        private void ExtractConnectionStringInfo(SqlConnection connection)
        {
            SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connection.ConnectionString);
            cbServers.Text = builder.DataSource;
            chkWindowsIdentity.Checked = builder.IntegratedSecurity;
            if (!chkWindowsIdentity.Checked)
            {
                txtLogin.Text = builder.UserID;
                txtPassword.Text = builder.Password;
            }
        }

        private void OnControlsUnfreezed(object sender, EventArgs e)
        {
            SetConnectButtonAvailability();
        }

        private void ConnectForm_Load(object sender, EventArgs e)
        {
            SetConnectButtonAvailability();
        }

        private void btnUpdateServers_Click(object sender, EventArgs e)
        {
            FreezeControlsForPerfomingRefreshCommand();
            ucLoadingProgress.Start();
            bwRefreshServerList.RunWorkerAsync();
        }

        private void FreezeControlsForPerfomingRefreshCommand()
        {
            _refreshOperationFreezer.Freeze();
        }

        private void UnfreezeControlsAfterPerfomingRefreshCommand()
        {
            _refreshOperationFreezer.Unfreeze();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            _connectOperationFreezer.Freeze();
            ucLoadingProgress.Start();
            bwConnectToDB.RunWorkerAsync();
        }

        private string GetSelectedServer()
        {
            object selectedValue = null;
            UIHelper.InvokeSafely(cbServers, delegate
                    {
                        selectedValue = GetSelectedValueFromServersComboBox();
                    });
            return selectedValue == null ? string.Empty : selectedValue.ToString();
        }

        private object GetSelectedValueFromServersComboBox()
        {
            return cbServers.Text;
        }

        private void bwRefreshServerList_DoWork(object sender, DoWorkEventArgs e)
        {
            AppConsole.WriteLine(Resources.RefreshingInformationAboutServers);

            DataTable serversTable = SqlDataSourceEnumerator.Instance.GetDataSources();

            AppConsole.WriteLine(string.Format(Resources.FoundServers, serversTable.Rows.Count.ToString()));
            e.Result = serversTable;
        }

        private void bwRefreshServerList_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                cbServers.Items.Clear();
                DataTable table = e.Result as DataTable;
                AddFoundServersToComboBox(table);
            }
            finally
            {
                UnfreezeControlsAfterPerfomingRefreshCommand();
                ucLoadingProgress.Finish();
                AppConsole.WriteLine(Resources.InformationAboutServersRefreshed);
            }
        }

        private void AddFoundServersToComboBox(DataTable table)
        {
            ConnectionStringsStorage storage = new ConnectionStringsStorage();
            storage.Load();
            foreach (DataRow item in table.Rows)
            {
                SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
                builder.DataSource = item[Constants.SqlServer.ServerNameColumnName].ToString();

                string connectionString = builder.ConnectionString;
                if (storage.Contains(builder.DataSource))
                {
                    connectionString = storage[builder.DataSource];
                }
                AddToServersComboBox(connectionString);
            }
        }

        private void bwConnectToDB_DoWork(object sender, DoWorkEventArgs e)
        {
            AppConsole.WriteLine(Resources.Connecting);
            string connectionString = CreateConnectionString();
            SqlConnection connection = new SqlConnection(connectionString);
            e.Result = connection;
            ConnectionHelper.OpenConnection(connection, true, true);
        }

        private string CreateConnectionString()
        {
            SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder();
            connectionStringBuilder[Constants.SqlServer.ConnectionStringServerItem] = GetSelectedServer();
            connectionStringBuilder[Constants.SqlServer.ConnectionStringTrustedConnectionItem] = chkWindowsIdentity.Checked;
            if (!chkWindowsIdentity.Checked)
            {
                connectionStringBuilder.UserID = txtLogin.Text;
                connectionStringBuilder.Password = txtPassword.Text;
            }
            if (chkRememberServer.Checked)
            {
                ConnectionStringsStorage storage = new ConnectionStringsStorage();
                storage.Save(connectionStringBuilder);
            }
            return connectionStringBuilder.ConnectionString;
        }

        private void bwConnectToDB_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                ucLoadingProgress.Finish();
                if (e.Error != null)
                {
                    AppConsole.WriteError(Resources.ErrorOccuredDuringOpeningConnection);
                    _connectionToDb = null;
                    Logging.Handle(e.Error);
                }
                else
                {
                    _connectionToDb = e.Result as SqlConnection;

                    if (_connectionToDb == null)
                    {
                        throw new InvalidOperationException(Resources.SQLConnectionWasDamaged);
                    }
                }
            }
            finally
            {
                _connectOperationFreezer.Unfreeze();
                DialogResult = DialogResult.OK;
                Close();
            }
        }

        private void cbServers_TextChanged(object sender, EventArgs e)
        {
            SetConnectButtonAvailability();
        }

        private void SetConnectButtonAvailability()
        {
            btnConnect.Enabled = !string.IsNullOrEmpty(cbServers.Text);
        }

        private void chkWindowsIdentity_CheckedChanged(object sender, EventArgs e)
        {
            pnlLoginPassword.Enabled = !chkWindowsIdentity.Checked;
        }

        private void cbServers_SelectedIndexChanged(object sender, EventArgs e)
        {
            ServersComboBoxItem item = cbServers.SelectedItem as ServersComboBoxItem;
            if (item != null)
            {
                ExtractConnectionStringInfo(item.Connection);
            }
        }

        private void ConnectionForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = !btnCancel.Enabled;
            }
        }
    }
}
